//!
/************************************************************************************************************
 * @file RBD3D9FXLibrary.cpp
 ************************************************************************************************************/

/************************************************************************************************************
 * Precompiled Header
 ************************************************************************************************************/
#include "RBD3D9RendererPCH.h"

/************************************************************************************************************
 * Includes
 ************************************************************************************************************/

#include "RBD3D9FXLibrary.h"

#include "RBD3D9Renderer.h"
#include "RBD3D9FXTechnique.h"

/************************************************************************************************************
 * Defines
 ************************************************************************************************************/

/************************************************************************************************************
 * Implementation
 ************************************************************************************************************/

/************************************************************************************************************
 * Constructor
 ************************************************************************************************************/
RBD3D9FXLibrary::RBD3D9FXLibrary(RBD3D9Renderer* pRenderer)
: m_pRenderer(pRenderer)
{
    pRenderer->AddResetFunction(RBFastDelegateBind(&RBD3D9FXLibrary::OnReset, this));
}

/************************************************************************************************************
 * Destructor
 ************************************************************************************************************/
RBD3D9FXLibrary::~RBD3D9FXLibrary()
{
    for (uint32 ui=0; ui < m_aEffectsCreated.size(); ++ui)
    {
        m_aEffectsCreated[ui].m_pEffect->Release();
        m_aEffectsCreated[ui].m_pEffect = 0;
    }
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
void RBD3D9FXLibrary::Read(const RBString& strFilename, std::vector<RBTechnique*>& vTechniques)
{
    Effect effect;
    effect.m_strFilename = strFilename;

    if (BuildEffect(effect))
    {
        for (uint32 uiTechnique=0; uiTechnique < effect.m_vTechniques.size(); ++uiTechnique)
        {
            vTechniques.push_back(effect.m_vTechniques[uiTechnique]);
        }
        m_aEffectsCreated.push_back(effect);
    }

}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
void RBD3D9FXLibrary::OnReset( bool bBeforeReset )
{
    for (uint32 ui=0; ui < m_aEffectsCreated.size(); ++ui)
    {
        if (bBeforeReset)
        {
            m_aEffectsCreated[ui].m_pEffect->Release();
            m_aEffectsCreated[ui].m_pEffect = 0;
            for (uint32 uiTechnique=0; uiTechnique < m_aEffectsCreated[ui].m_vTechniques.size(); ++uiTechnique)
            {
                m_aEffectsCreated[ui].m_vTechniques[uiTechnique]->m_pEffect = NULL;
                m_aEffectsCreated[ui].m_vTechniques[uiTechnique]->m_hTechnique = NULL;
            }
        }
        else
        {
            BuildEffect(m_aEffectsCreated[ui], false);
        }
    }
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
bool RBD3D9FXLibrary::BuildEffect( Effect& effect, bool bCreateTechniques )
{
    ID3DXBuffer* pBuffer = NULL;
    ID3DXEffect* pEffect = NULL;
    D3DXHANDLE   hTechnique = NULL;

    effect.m_pEffect = NULL;
    uint32 uiTechnique = 0;
    if (SUCCEEDED(D3DXCreateEffectFromFile(RBD3D9Renderer::GetSingleton()->GetD3DDevice(), effect.m_strFilename.c_str(), NULL, NULL, 
        D3DXFX_DONOTSAVESTATE | D3DXFX_DONOTSAVESAMPLERSTATE | D3DXFX_DONOTSAVESHADERSTATE,
        NULL, &pEffect, &pBuffer)))
    {
        effect.m_pEffect = pEffect;
        while (SUCCEEDED(pEffect->FindNextValidTechnique(hTechnique, &hTechnique)))
        {
            if (hTechnique == NULL)
            {
                break;
            }

            if (bCreateTechniques)
            {
                RBD3D9FXTechnique* pTechnique = RBNew RBD3D9FXTechnique(m_pRenderer, pEffect, hTechnique);
                if (!pTechnique->Load())
                {
                    RBDelete pTechnique;
                    pTechnique = NULL;
                }

                if (pTechnique)
                {
                    effect.m_vTechniques.push_back(pTechnique);
                }
            }
            else
            {
                RBD3D9FXTechnique* pTechnique = effect.m_vTechniques[uiTechnique++];
                pTechnique->m_pEffect = pEffect;
                pTechnique->m_hTechnique = hTechnique;
                pTechnique->Load(true);
            }
        }
        return true;
    }

    if (pBuffer)
    {
        free(pBuffer);
    }

    return false;
}

/************************************************************************************************************/
